<template>
  <div
    v-if="!initializing"
    class="cc-flow cc-flex-row cc-grow-height"
  >
    <el-tabs v-model="tabName" class="fit-box full-height">
      <el-tab-pane name="base" :label="flowNode.name ? flowNode.name : '流程明细'" class="fit-box full-height">
        <div class="base-body">
          <div class="base-main">
            <div class="base-handled">
              <el-collapse v-model="collapseNames" v-if="handledNodeList.length > 0" style="margin-bottom: 20px">
                <el-collapse-item
                  v-for="(item, index) in handledNodeList"
                  :name="index"
                  :key="item.id"
                >
                  <template #title>
                    <div class="collapse-title">
                      <span class="title-item">流程节点：{{ item.currFlowNodeName }}</span>
                      <span class="title-item">处理部门：{{ item.dealOrgName || '' }}</span>
                      <span class="title-item">处理人：{{ item.dealManName || '' }}{{}}
                        <span
                          v-if="item.flowNode
                            && item.flowNode.signatureType
                            && item.flowNode.signatureType !== '0'
                            && item.signatureId"
                        >
                          <el-tooltip raw-content placement="bottom" effect="light">
                            <template #content>
                              <div class="image">
                                <img :src="imagePath + item.signatureId" alt />
                              </div>
                            </template>
                            <span style="color: #26c2cf;margin-left: 5px">(签名)</span>
                          </el-tooltip>
                        </span>
                      </span>
                      <span class="title-item">处理时间：{{ date.formatLongDate(item.endTime) }}</span>
                      <span class="title-item-flow" v-if="item.subInstId && item.subInstTitle">
                        子流程：
                        <span class="sub-flow-name" @click="e => showFlow(e, item)">
                          {{ item.subInstId && item.subInstTitle ? item.subInstTitle : '' }}
                        </span>
                      </span>
                    </div>
                  </template>
                  <Page
                    :dataPageId="item.flowNode.viewPageId"
                    :inputParam="item.inputParam"
                    :disabled="true"
                  />
                </el-collapse-item>
              </el-collapse>
            </div>
            <Page
              v-if="props.options.start || pendingInstNodeId"
              ref="pageRef"
              :dataPageId="editPageId"
              :copyData="copyData"
              :inputParam="inputParam"
              :initData="initData"
            >
              <signature
                v-if="(props.options.start || pendingInstNodeId)
                  && flowNode.signatureType && flowNode.signatureType !== '0'"
                v-model="signatureId"
                :signatureType="flowNode.signatureType"
              />
            </Page>
          </div>
          <div class="base-footer" v-if="!dialogMode">
            <span>
              <el-button
                v-if="canCompleted && pendingInstNodeId"
                type="danger"
                :loading="submitLoading"
                @click="completed"
              >办结</el-button>
              <el-button
                v-if="canRetrieve && pendingInstNodeId"
                type="warning"
                :loading="submitLoading"
                @click="retrieve"
              >取回</el-button>
              <el-button
                v-if="flowNode && flowNode.id && (props.options.start || pendingInstNodeId)"
                type="success"
                :loading="submitLoading"
                @click="submit(2)"
              >暂存</el-button>
              <el-button
                v-if="flowNode && flowNode.id && (props.options.start || pendingInstNodeId)"
                type="primary"
                :loading="submitLoading"
                @click="submit('')"
              >提交</el-button>
            </span>
          </div>
        </div>
      </el-tab-pane>
      <el-tab-pane name="flow" label="流程信息" class="fit-box full-height">
        <keep-alive>
          <component
            :is="tabName === 'flow' ? toRaw(Chart) : null"
            :xml="flow.xmlText"
            :highlightList="highlightList"
            :handledList="handledList"
          ></component>
        </keep-alive>
      </el-tab-pane>
      <el-tab-pane name="history" label="处理记录" class="fit-box full-height">
        <el-table
          :show-overflow-tooltip="true"
          :data="taskNodeList"
          :border="true"
        >
          <el-table-column
            v-for="(column, index) in columns"
            align="center"
            header-align="center"
            :key="index"
            :label="column.label"
            :width="column.width"
            :min-width="column.minWidth"
            :show-overflow-tooltip="true"
          >
            <template #default="scope">
              <span>{{column.formatter ? column.formatter(scope.row) : (scope.row[column.prop] || '')}}</span>
            </template>
          </el-table-column>
        </el-table>
      </el-tab-pane>
    </el-tabs>

    <el-dialog
      v-model="subFlowVisible"
      append-to-body
      destroy-on-close
      draggable
      :close-on-click-modal="false"
      :fullscreen="dialogFullscreen"
      :class="['cc-page-comp-dialog', 'padding-10']"
    >
      <template #header>
        <div class="header" @dblclick="dialogFullscreen=!dialogFullscreen">
          <div class="title">{{subFlowTitle}}</div>
          <div class="button">
            <cc-icon
              v-if="!dialogFullscreen"
              iconId="018dca8cad1b28075ecd"
              @click="dialogFullscreen=true"
              title="最大化"
            />
            <cc-icon
              v-if="dialogFullscreen"
              iconId="018dca8cad1b9b03c47f"
              @click="dialogFullscreen=false"
              title="缩小"
            />
          </div>
        </div>
      </template>
      <Deal :options="subFlowOptions" />
      <template #footer>
        <el-button
          size="default"
          type="info"
          @click="subFlowVisible = false"
        >关闭</el-button>
        <el-button
          v-for="(button, index) in dialogButtonList"
          :key="index"
          size="default"
          class="base-button"
          :type="button.type || 'primary'"
          :style="button.color ? {
            'color': 'white',
            'background-color': button.color,
            'border': '1px solid ' + button.color
          } : {}"
          :loading="button.loading"
          @click="clickButton(button)"
        >{{button.name}}</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: 'Deal'
};
</script>

<script setup>
import {ref, onMounted, toRaw, inject, provide} from 'vue';
import api from "@/http/api";
import Page from "@/codeless/view/page.vue";
import Chart from "@/flow/chart.vue";
import { ElMessage, ElMessageBox } from "element-plus";
import date from "@/utils/date";
import Signature from './signature.vue';

const props = defineProps({
  options: {
    type: Object,
    default: () => {
      return {
        flowId: String,
        start: {
          type: Boolean,
          default: false
        },
        instNodeId: String,
        parentInstId: String,
        parentInstNodeId: String,
        initData: Object
      }
    }
  }
});

const initializing = ref(true);
const tabName = ref('base');
const flow = ref({});
const flowNode = ref({});
const flowNodeList = ref([]);
const flowLineList = ref([]);
const editPageId = ref('');
const inputParam = ref({});
const copyData = ref(false);
const initData = ref({});
const flowInstId = ref('');
const flowInst = ref({});
const flowInstNode = ref({});
const instNodeId = ref('');
const pendingInstNodeId = ref('');
const highlightList = ref([]);
const handledList = ref([]);
const flowInstNodeList = ref([]);
const taskNodeList = ref([]);
const handledNodeList = ref([]);
const canCompleted = ref(false);
const canRetrieve = ref(false);
const collapseNames = ref([0]);
const pageRef = ref();
const submitLoading = ref(false);
const formData = ref({
  pageId: '',
  pageData: {},
  flowData: {}
});
const signatureId = ref();
const imagePath = ref(import.meta.env.VITE_IMAGE_PATH);
const dialogMode = inject('dialogMode', false);
const showDialogButton = inject('showDialogButton', () => {});
const menuId = inject('menuId');
provide('permitMenuId', menuId);

const dialogButtonList = ref([]);
provide('showDialogButton', (buttonList) => {
  dialogButtonList.value = buttonList;
});

const clickButton = (button) => {
  button.loading = true;
  try {
    button.click();
  } catch (e) {
    console.log(e);
  } finally {
    button.loading = false;
  }
};

const columns = ref([
  {prop: "currFlowNodeName", label: "流程节点", minWidth: 120},
  {prop: "dealOrgName", label: "处理部门", minWidth: 120},
  {prop: "dealManName", label: "处理人", minWidth: 110},
  {prop: "startTime", label: "接收时间", minWidth: 120, formatter:
    row => date.formatLongDate(row.startTime)
  },
  {prop: "endTime", label: "处理时间", minWidth: 120, formatter:
    function(row) {
      return row.dealStatus === '99' ? date.formatLongDate(row.endTime) : '';
    }
  },
  {prop: "id", label: "处理耗时", minWidth: 120, formatter:
    function(row) {
      if (row.dealStatus === '99' && row.startTime && row.endTime) {
        return date.getDiffTime(row.startTime, row.endTime);
      } else {
        return '';
      }
    }
  }
]);

const loadData = (data) => {
  initializing.value = true;

  canCompleted.value = false;
  canRetrieve.value = false;
  flow.value = {};
  flowNode.value = {};
  flowInst.value = {};
  editPageId.value = '';
  copyData.value = false;
  inputParam.value = data.inputParam || {};
  flowInstId.value = '';
  instNodeId.value = '';
  flowNodeList.value = [];
  flowLineList.value = [];
  flowInstId.value = '';
  instNodeId.value = '';
  pendingInstNodeId.value = '';
  initData.value = data.initData || {};

  if (!data.flowId && !data.instId && !data.instNodeId) {
    initializing.value = false;
    return;
  }

  const param = {
    startFlow: data.start,
    flowId: data.flowId,
    instId: data.instId,
    instNodeId: data.instNodeId
  };
  api.post('/flow/bpmn/queryBy', param).then(res => {
    if (res && res.data) {
      canCompleted.value = res.data.canCompleted || false;
      canRetrieve.value = res.data.canRetrieve || false;
      flow.value = res.data.flow || {};
      flowNode.value = res.data.flowNode || {};
      flowInst.value = res.data.flowInst || {};
      flowInstNode.value = res.data.flowInstNode || {};
      editPageId.value = flowNode.value.editPageId || '';
      flowNodeList.value = res.data.flowNodeList || [];
      flowLineList.value = res.data.flowLineList || [];
      flowInstNodeList.value = res.data.flowInstNodeList || [];

      if (flowNode.value.editPageDataParamId && flowInstNode.value.dataId) {
        copyData.value = flowInstNode.value.copyData || false;
        inputParam.value[flowNode.value.editPageDataParamId] = flowInstNode.value.dataId;
      }
      flowInstId.value = res.data.flowInstId || '';
      instNodeId.value = res.data.instNodeId || '';
      pendingInstNodeId.value = res.data.pendingInstNodeId || '';

      flowInstNodeList.value.forEach(instNode => {
        const flowNode = flowNodeList.value.find(item => item.id === instNode.currFlowNodeId);
        if (flowNode) {
          instNode.flowNode = flowNode;
          instNode.inputParam = {};
          if (flowNode.viewPageDataParamId && instNode.dataId) {
            instNode.inputParam[flowNode.viewPageDataParamId] = instNode.dataId;
          }
        }
      });

      initTaskNodeList(flowInstNodeList.value);
      initHandledNodeList(flowInstNodeList.value);

      initButton();
      initFlowChart(res.data || {});
    }
    initializing.value = false;
  }).catch((e) => {
    console.log(e)
    initializing.value = false;
  });
};

const initFlowChart = (data) => {
  highlightList.value = [];
  handledList.value = [];

  // 当前节点
  if (data.flowNode && data.flowNode.code) {
    highlightList.value.push(data.flowNode.code);
  }

  // 开始节点
  for (let node of flowNodeList.value) {
    if (node.type === '01') {
      handledList.value.push(node.code);
    }
  }

  // 开始节点出来的线路
  for (let flowLine of flowLineList.value) {
    if (flowLine.preNodeType === '01') {
      handledList.value.push(flowLine.code);
    }
  }

  for (let flowInstNode of flowInstNodeList.value) {
    // 高亮所有未完成的节点
    if (flowInstNode.dealStatus !== '99') {
      const flowNode = flowNodeList.value.find(node => node.id === flowInstNode.currFlowNodeId);
      if (flowNode) {
        highlightList.value.push(flowNode.code);
      }
    } else {
      if (flowInstNode.currFlowNodeId) {
        const flowNode = flowNodeList.value.find(item => item.id === flowInstNode.currFlowNodeId);
        if (flowNode) {
          handledList.value.push(flowNode.code);
        }
      }
    }

    // 实例节点已走过的线路
    if (!flowInstNode.lineId) continue;
    const flowLine = flowLineList.value.find(item => item.id === flowInstNode.lineId);
    if (flowLine) {
      handledList.value.push(flowLine.code);
    }
  }
};

const initButton = () => {
  if (dialogMode) {
    const buttonList = [];

    if (pendingInstNodeId.value
        && !flowInstNode.value.subInstId
        && flowNode.value
        && flowNode.value.id
        && flowNode.value.canSubFlow === '1'
        && flowNode.value.subFlowId) {
      buttonList.push({
        name: '发起子流程',
        type: 'primary',
        click: () => {
          openSubFlow();
        }
      });
    }

    if (canCompleted.value && pendingInstNodeId.value) {
      buttonList.push({
        name: '办结',
        type: 'danger',
        click: () => {
          completed();
        }
      });
    }

    if (canRetrieve.value && pendingInstNodeId.value) {
      buttonList.push({
        name: '取回',
        type: 'warning',
        click: () => {
          retrieve();
        }
      });
    }

    if (flowNode.value && flowNode.value.id && (props.options.start || pendingInstNodeId.value)) {
      buttonList.push({
        name: '暂存',
        type: 'success',
        click: () => {
          submit(2);
        }
      });

      buttonList.push({
        name: '提交',
        type: 'primary',
        click: () => {
          submit();
        }
      });
    }

    showDialogButton(buttonList);
  } else {
    showDialogButton([]);
  }
};

const subFlowTitle = ref('');
const dialogFullscreen = ref(true);
const subFlowVisible = ref(false);
const subFlowOptions = ref({});
const openSubFlow = async() => {
  if (!flowInst.value || !flowInst.value.id || !instNodeId.value) {
    ElMessage.error("非待办节点，不能发起子流程！");
    return;
  }

  if (!flowNode.value || flowNode.value.canSubFlow !== '1' || !flowNode.value.subFlowId) {
    ElMessage.error("当前节点信息不正确！");
    return;
  }

  const flow = await api.post('/flow/flow/queryBy', {id: flowNode.value.subFlowId});
  if (!flow || !flow.data) {
    ElMessage.error("子流程已废弃！");
    return;
  }

  subFlowTitle.value = '发起流程【' + flow.data.name + '】';
  let params = {};
  if (flowNode.value.subFlowParam) {
    const res = await api.post("/flow/bpmn/queryNodeDataList", { instId: flowInst.value.id});
    if (res.data) {
      params = parseFlowParam(flowNode.value.subFlowParam, res.data || {});
    }
  }

  subFlowOptions.value = {
    flowId: flowNode.value.subFlowId,
    start: true,
    parentInstId: flowInst.value.id,
    parentInstNodeId: instNodeId.value,
    initData: params
  };
  subFlowVisible.value = true;
};

const parseFlowParam = (jsonStr, dataMap) => {
  if (!jsonStr || !dataMap) return {};

  const list = JSON.parse(jsonStr);
  const result = {};
  list.forEach(item => {
    if (!item
      || !item.nodeId
      || !item.sourceFieldName
      || !item.targetFieldName
      || !dataMap[item.nodeId]) return;
    const data = dataMap[item.nodeId];
    result[item.targetFieldName] = data[item.sourceFieldName];
  });
  return result;
};

const showFlow = (event, data) => {
  event.preventDefault();
  event.stopPropagation();

  subFlowTitle.value = '查看子流程【' + data.subInstTitle + '】';
  subFlowOptions.value = { instId: data.subInstId };
  subFlowVisible.value = true;
};

const completed = () => {
  if (submitLoading.value) return;
  if (!pageRef.value) return;

  ElMessageBox.confirm("办结后流程将非正常终止，请确认是否办结？", "提示", { type: "warning" }).then(() => {
    pageRef.value.validate(async (valid) => {
      if (!valid) return;

      formData.value.pageId = editPageId.value;
      formData.value.pageData = pageRef.value.getData();
      formData.value.flowData = {
        flowId: flow.value.id,
        nodeId: flowNode.value.id,
        instId: flowInst.value.id,
        instNodeId: pendingInstNodeId.value,
      }

      submitLoading.value = true;
      api.post('/flow/bpmn/saveCompleted', formData.value).then(res => {
        submitLoading.value = false;
        ElMessage.success(res.message);
        loadData({instNodeId: res.data.id, dataId: res.data.dataId});
      }).catch(() => submitLoading.value = false);
    });
  });
};

const retrieve = () => {
  if (submitLoading.value) return;
  if (!pageRef.value) return;

  ElMessageBox.confirm("请确认是否取回？", "提示", { type: "warning" }).then(() => {
    pageRef.value.validate(async (valid) => {
      if (!valid) return;

      formData.value.pageId = editPageId.value;
      formData.value.pageData = pageRef.value.getData();
      formData.value.flowData = {
        flowId: flow.value.id,
        nodeId: flowNode.value.id,
        instId: flowInstId.value,
        instNodeId: pendingInstNodeId.value,
      }

      submitLoading.value = true;
      api.post('/flow/bpmn/saveRetrieve', formData.value).then(res => {
        submitLoading.value = false;
        ElMessage.success(res.message);
        loadData({instNodeId: res.data.id, dataId: res.data.dataId});
      }).catch(() => submitLoading.value = false);
    });
  });
};

const submit = (submitFlag) => {
  if (submitLoading.value) return;
  if (!pageRef.value) return;

  if ((submitFlag || 0) === 2) {
    ElMessageBox.confirm("请确认是否暂存？", "提示", { type: "warning" }).then(() => {
      submitData(submitFlag);
    });
  } else {
    pageRef.value.validate(async (valid) => {
      if (!valid) return;

      if (flowNode.value
          && flowNode.value.signatureType
          && flowNode.value.signatureType !== '0'
          && !signatureId.value) {
        ElMessage.error("请先录入/选择电子签名！");
        return;
      }
      ElMessageBox.confirm("请确认是否提交？", "提示", { type: "warning" }).then(() => {
        submitData(submitFlag);
      });
    });
  }
};

const submitData = (submitFlag) => {
  formData.value.submitFlag = submitFlag || '';
  formData.value.signatureId = signatureId.value || '';
  formData.value.pageId = editPageId.value;
  formData.value.pageData = pageRef.value.getData();
  formData.value.flowData = {
    flowId: flow.value.id,
    nodeId: flowNode.value.id,
    instId: flowInstId.value,
    instNodeId: instNodeId.value,
    parentInstId: props.options.start ? props.options.parentInstId : '',
    parentInstNodeId: props.options.start ? props.options.parentInstNodeId : ''
  }

  submitLoading.value = true;
  api.post('/flow/bpmn/save', formData.value).then(res => {
    submitLoading.value = false;
    ElMessage.success(res.message);
    loadData({instNodeId: res.data.id, dataId: res.data.dataId});
  }).catch(() => submitLoading.value = false);
};

const initHandledNodeList = (list) => {
  const filterList = list.filter(item => item.dealStatus === '99' && item.flowNode && item.flowNode.type === '10');
  filterList.sort((a, b) => {
    if (a.flowNode && b.flowNode) {
      if ((a.flowNode.ordinal || 0) === (b.flowNode.ordinal || 0)) {
        return b.createTime - a.createTime;
      } else {
        return (a.flowNode.ordinal || 0) - (b.flowNode.ordinal || 0);
      }
    } else {
      if (a.createTime === b.createTime) {
        return a.id.localeCompare(b.id);
      } else {
        return a.createTime - b.createTime;
      }
    }
  });
  handledNodeList.value = filterList;
};

const initTaskNodeList = (list) => {
  const filterList = list.filter(item => item.flowNode && item.flowNode.type === '10');
  filterList.sort((a, b) => {
    if (a.createTime === b.createTime) {
      return a.id.localeCompare(b.id);
    } else {
      return a.createTime - b.createTime;
    }
  });
  taskNodeList.value = filterList;
};

onMounted(() => {
  loadData(props.options);
});
</script>

<style scoped lang="scss">
.base-body {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  height: 1px;
  overflow: hidden;
  overflow-y: auto;
  padding-right: 5px;
  .base-main {
    flex-grow: 1;
    display: flex;
    flex-direction: column;
    .collapse-title {
      display: flex;
      flex-direction: row;
      overflow: hidden;
      .title-item {
        display: flex;
        flex-direction: row;
        margin-right: 20px;
        flex-wrap: nowrap;
        flex-shrink: 0;
        text-overflow: ellipsis;
      }
      .title-item-flow {
        display: flex;
        flex-direction: row;
        flex-wrap: nowrap;
        overflow: hidden;
        white-space: nowrap;
        .sub-flow-name {
          cursor: pointer;
          color: var(--el-color-primary);
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }
      }
    }
    :deep(.cc-page) {
      min-height: unset!important;
      height: auto !important;
      padding: unset!important;
    }
    :deep(.el-collapse-item__content) {
      padding-bottom: 10px!important;
    }
  }
  .base-footer {
    text-align: right;
    .base-button:not(.is-disabled):hover{
      filter: opacity(0.7);
    }
    .base-label {
      display: block;
      border-radius: 5px;
      height: 24px;
      line-height: 24px;
      padding: 4px 6px;
      color: white;
    }
  }
}
.image {
  width: 100px;
  height: 30px;
  img {
    max-width: 100%; /* 图片最大宽度不超过容器 */
    max-height: 100%; /* 图片最大高度不超过容器 */
    object-fit: contain; /* 等比例缩放图片 */
  }
}
</style>
